/** * Copyright (c) 2008-2012 University of Illinois at Urbana-Champaign. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package edu.illinois.compositerefactorings.refactorings; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.ToolFactory; import org.eclipse.jdt.core.compiler.IScanner; import org.eclipse.jdt.core.compiler.ITerminalSymbols; import org.eclipse.jdt.core.compiler.InvalidInputException; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.Block; import org.eclipse.jdt.core.dom.BodyDeclaration; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.Javadoc; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword; import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; import org.eclipse.jdt.core.dom.rewrite.ListRewrite; import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; import org.eclipse.jdt.internal.corext.dom.TokenScanner; import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; import org.eclipse.jdt.internal.corext.refactoring.changes.CreateCompilationUnitChange; import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil; import org.eclipse.jdt.internal.corext.util.JavaModelUtil; import org.eclipse.jdt.internal.ui.JavaPlugin; import org.eclipse.jdt.ui.CodeGeneration; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.Document; import org.eclipse.ltk.core.refactoring.resource.ResourceChange; import org.eclipse.text.edits.TextEdit; @SuppressWarnings({ "restriction", "unchecked" }) public class NewClassCreator { private String fClassName; private IPackageFragment fPackageFragment; private Type fSuperclassType; public NewClassCreator(String fClassName, IPackageFragment fPackageFragment, Type fSuperclassType) { this.fClassName= fClassName; this.fPackageFragment= fPackageFragment; this.fSuperclassType= fSuperclassType; } public String getClassName() { return fClassName; } public IPackageFragment getPackageFragment() { return fPackageFragment; } public List<ResourceChange> createTopLevelParameterObject() throws CoreException { List<ResourceChange> changes= new ArrayList<ResourceChange>(); ICompilationUnit unit= getPackageFragment().getCompilationUnit(getClassName() + JavaModelUtil.DEFAULT_CU_SUFFIX); Assert.isTrue(!unit.exists()); IJavaProject javaProject= unit.getJavaProject(); ICompilationUnit workingCopy= unit.getWorkingCopy(null); try { // create stub with comments and dummy type String lineDelimiter= StubUtility.getLineDelimiterUsed(javaProject); String fileComment= getFileComment(workingCopy, lineDelimiter); String typeComment= getTypeComment(workingCopy, lineDelimiter); String content= CodeGeneration.getCompilationUnitContent(workingCopy, fileComment, typeComment, "class " + getClassName() + "{}", lineDelimiter); //$NON-NLS-1$ //$NON-NLS-2$ workingCopy.getBuffer().setContents(content); CompilationUnitRewrite cuRewrite= new CompilationUnitRewrite(workingCopy); ASTRewrite rewriter= cuRewrite.getASTRewrite(); CompilationUnit root= cuRewrite.getRoot(); AST ast= cuRewrite.getAST(); ImportRewrite importRewrite= cuRewrite.getImportRewrite(); if (fSuperclassType != null) { importRewrite.addImport(fSuperclassType.resolveBinding()); } // retrieve&replace dummy type with real class ListRewrite types= rewriter.getListRewrite(root, CompilationUnit.TYPES_PROPERTY); ASTNode dummyType= (ASTNode)types.getOriginalList().get(0); TypeDeclaration classDeclaration= createClassDeclaration(getClassName(), cuRewrite); classDeclaration.modifiers().add(ast.newModifier(ModifierKeyword.PUBLIC_KEYWORD)); Javadoc javadoc= (Javadoc)dummyType.getStructuralProperty(TypeDeclaration.JAVADOC_PROPERTY); rewriter.set(classDeclaration, TypeDeclaration.JAVADOC_PROPERTY, javadoc, null); types.replace(dummyType, classDeclaration, null); // Apply rewrites and discard workingcopy // Using CompilationUnitRewrite.createChange() leads to strange // results String charset= ResourceUtil.getFile(unit).getCharset(false); Document document= new Document(content); try { rewriter.rewriteAST().apply(document); TextEdit rewriteImports= importRewrite.rewriteImports(null); rewriteImports.apply(document); } catch (BadLocationException e) { throw new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), RefactoringCoreMessages.IntroduceParameterObjectRefactoring_parameter_object_creation_error, e)); } String docContent= document.get(); CreateCompilationUnitChange compilationUnitChange= new CreateCompilationUnitChange(unit, docContent, charset); changes.add(compilationUnitChange); } finally { workingCopy.discardWorkingCopy(); } return changes; } public TypeDeclaration createClassDeclaration(String declaringType, CompilationUnitRewrite cuRewrite) throws CoreException { AST ast= cuRewrite.getAST(); TypeDeclaration typeDeclaration= ast.newTypeDeclaration(); typeDeclaration.setName(ast.newSimpleName(fClassName)); if (fSuperclassType != null) { Type superclassASTNode= (Type)Type.copySubtree(typeDeclaration.getAST(), fSuperclassType); typeDeclaration.setSuperclassType(superclassASTNode); } List<BodyDeclaration> body= typeDeclaration.bodyDeclarations(); MethodDeclaration constructor= createConstructor(declaringType, cuRewrite); body.add(constructor); return typeDeclaration; } private MethodDeclaration createConstructor(String declaringTypeName, CompilationUnitRewrite cuRewrite) throws CoreException { AST ast= cuRewrite.getAST(); ICompilationUnit unit= cuRewrite.getCu(); IJavaProject project= unit.getJavaProject(); MethodDeclaration methodDeclaration= ast.newMethodDeclaration(); methodDeclaration.setName(ast.newSimpleName(fClassName)); methodDeclaration.setConstructor(true); methodDeclaration.modifiers().add(ast.newModifier(ModifierKeyword.PUBLIC_KEYWORD)); String lineDelimiter= StubUtility.getLineDelimiterUsed(unit); if (createComments(project)) { String comment= CodeGeneration.getMethodComment(unit, declaringTypeName, methodDeclaration, null, lineDelimiter); if (comment != null) { Javadoc doc= (Javadoc)cuRewrite.getASTRewrite().createStringPlaceholder(comment, ASTNode.JAVADOC); methodDeclaration.setJavadoc(doc); } } Block block= ast.newBlock(); methodDeclaration.setBody(block); return methodDeclaration; } protected String getFileComment(ICompilationUnit parentCU, String lineDelimiter) throws CoreException { if (StubUtility.doAddComments(parentCU.getJavaProject())) { return CodeGeneration.getFileComment(parentCU, lineDelimiter); } return null; } protected String getTypeComment(ICompilationUnit parentCU, String lineDelimiter) throws CoreException { if (StubUtility.doAddComments(parentCU.getJavaProject())) { StringBuffer typeName= new StringBuffer(); typeName.append(getClassName()); String[] typeParamNames= new String[0]; String comment= CodeGeneration.getTypeComment(parentCU, typeName.toString(), typeParamNames, lineDelimiter); if (comment != null && isValidComment(comment)) { return comment; } } return null; } private boolean isValidComment(String template) { IScanner scanner= ToolFactory.createScanner(true, false, false, false); scanner.setSource(template.toCharArray()); try { int next= scanner.getNextToken(); while (TokenScanner.isComment(next)) { next= scanner.getNextToken(); } return next == ITerminalSymbols.TokenNameEOF; } catch (InvalidInputException e) { } return false; } private boolean createComments(IJavaProject project) { return StubUtility.doAddComments(project); } }